<?php


namespace App\Exports;

use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Support\Facades\DB;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\RegistersEventListeners;
use Maatwebsite\Excel\Concerns\WithCustomStartCell;


/**
 * Class BookCatalogExport29
 * @package App\Exports
 * 全引目录
 *
 * 整体实现方法：
 * 第一步： 先把全部 卷内数据渲染到 excel ，中间记下需要插入 头部三行的row位置，和各空行插入点位置
 * 第二步:  插入空行
 * 第三步： 插入头部三行
 *
 */
class FullIndexExport implements FromCollection, WithCustomStartCell, ShouldQueue
{
    use Exportable, RegistersEventListeners;

    const FILE_TYPE = 25;   //全引目录
    const BOOK_TITLE_ATTR = 30;   //档号、案卷题名、总页数、保管期限、备注
    const BOOK_TITLE_INFO = 32;   //案卷信息
    const CATALOG_TITLE_ATTR = 27;   //卷内标题属性
    const DATA_ROW_HEIGHT = 27;   //数据行
    const REDIS_EXPIRE_TIME = 1200; //redis有效期

    protected $partCompanyId;     //参见单位ID
    protected $projectClassifyId; //参见单位ID
    protected $bookTitleIds;      //选择的案卷
    protected $column;            //总行数
    protected $headerIndexKey;    //头部三行序号起点
    protected $headerIndexTmp;    //暂存头部三行位置
    protected $redisKey;          //随机字符串
    protected $childScope;        //单位工程名称
    protected $firstHeaderKey;
    protected $tmp15;

    public function __construct($partCompanyId, $projectClassifyId, $bookTitleIds, $childScope)
    {
        $this->redisKey          = get_rand_str('export_fullIndex_tmp'); //创造个临时存储redis，用完销毁
        $this->partCompanyId     = $partCompanyId;
        $this->projectClassifyId = $projectClassifyId;
        $this->bookTitleIds      = to_array($bookTitleIds);
        $this->headerIndexKey    = 'I_header_index:' . $this->redisKey;
        $this->headerIndexTmp    = 'I_header_index_tmp:' . $this->redisKey;
        $this->firstHeaderKey    = 'I_first:' . $this->redisKey; //第一个案卷
        $this->tmp15             = 'I_tmp15:' . $this->redisKey; //用来存一个临时数据，excel每增加15行
        $this->childScope        = $childScope;
    }

    public function collection()
    {
        $suffix = $this->partCompanyId . '_' . $this->projectClassifyId;
        $list = DB::table("book_titles_{$suffix}")->from("book_titles_{$suffix} as bt")
            ->leftJoin("book_catalogs_{$suffix} as bc", 'bt.id', '=', 'bc.book_title_id')
            ->select('bt.id', 'bt.archives_no', 'bt.title as bt_title', 'bc.book_title_id', 'bc.serial_no', 'bt.store_period', 'bc.file_number', 'bc.director', 'bc.title', 'bc.c_date', 'bc.page_num', 'bc.remark')
            ->whereIn('bt.id', $this->bookTitleIds)
            ->whereNull('bt.deleted_at')
            ->whereNull('bc.deleted_at')
            ->orderBy('bt.serial_no')
            ->get()
            ->groupBy('book_title_id');

        //初始化插入的第一个 头部三行 插入点
        redis()->lpush($this->headerIndexKey, 1);
        redis()->set($this->headerIndexTmp, 1);
        redis()->set($this->firstHeaderKey, 1); //设置个临时变量，只用于第一个头部写入判断

        $resultList = [];
        $tmpKey     = $this->tmp15;
        redis()->set($tmpKey, 0); //设置个临时变量，记录达到15条数据，就插入三行头

        foreach ($list as $val) { //遍历获得每一个案卷的卷内
            $catalogs    = json_decode($val, true);
            $bookTitleId = $catalogs[0]['book_title_id'];
            if (empty($bookTitleId)) {
                continue;  //如果某个案卷为空，略过
            };
            $catalogCount = count($catalogs); //卷内数量
            $pageNum      = ceil($catalogCount / 15); //要分成几页（向上取整）
            $remainder    = $catalogCount % 15; //余数
            $emptyRows    = 15 - $remainder; //最后一页卷内需要添加多少空行
            for ($i = 1; $i <= $pageNum; $i++) { //有几页，就把档案号加进去几次
                redis()->incrby($this->headerIndexTmp, 19);
                $headerRows = redis()->get($this->headerIndexTmp);
                redis()->lpush($this->headerIndexKey, $headerRows); //头部三行插入点存进去
            }
            $maxSerialNo = max(array_column($catalogs, 'serial_no')); //获取这个案卷里面的最大序号
            foreach ($catalogs as $val2) {
                //增加头部三行
                if (redis()->get($this->firstHeaderKey) == 1) { //这里只会执行一次
                    $resultList = $this->addHeader($resultList, $val2);
                    redis()->incrby($this->firstHeaderKey, 1);
                }
                if (redis()->get($tmpKey) == 15) {
                    $resultList = $this->addHeader($resultList, $val2);
                    redis()->set($tmpKey, 0); //重置为0
                }
                //增加卷内数据
                $arr['number']      = $val2['serial_no'];
                $arr['file_number'] = format_str($val2['file_number']);
                $arr['title']       = format_str($val2['title']);
                $arr['page_num']    = $val2['page_num'];
                $arr['remark']      = ''; //备注留空
                $resultList[]       = $arr;
                if ($val2['serial_no'] && is_numeric($val2['serial_no'])) {
                    redis()->incrby($tmpKey, 1);
                }
                //增加空行
                if ($maxSerialNo == $val2['serial_no']) { //最后一行
                    if ($remainder) { //有余数
                        $resultList = $this->addEmptyRows($resultList, $emptyRows);
                        redis()->incrby($tmpKey, $emptyRows);
                    }
                }
            }
        }
        //用完清除
        redis()->del($this->tmp15);
        redis()->del($this->firstHeaderKey);
        redis()->expire($this->headerIndexKey, self::REDIS_EXPIRE_TIME);
        redis()->expire($this->headerIndexTmp, self::REDIS_EXPIRE_TIME);
        $this->column = count($resultList);

        return collect($resultList);
    }

    /**
     * 添加表头
     * @author: lxk
     * @date: 2023/7/12 17:37
     */
    public function addHeader($resultList, $val2)
    {
        $header1['number']      = '全  引  目  录';
        $header1['file_number'] = '';
        $header1['title']       = '';
        $header1['page_num']    = '';
        $header1['remark']      = '';

        $resultList[] = $header1;

        $header2['number']      = '档    号';
        $header2['file_number'] = '';
        $header2['title']       = '案卷题名';
        $header2['page_num']    = '保管
期限';
        $header2['remark']      = '备注';

        $resultList[] = $header2;

        $header3['number']      = $val2['archives_no'];
        $header3['file_number'] = '';
        $header3['title']       = $val2['bt_title'];
        $header3['page_num']    = $val2['store_period'];
        $header3['remark']      = $val2['remark'];

        $resultList[] = $header3;

        $header4['number']      = '序号';
        $header4['file_number'] = '文件
编号';
        $header4['title']       = '文件题名';
        $header4['page_num']    = '页号';
        $header4['remark']      = '备注';
        $resultList[]           = $header4;

        return $resultList;
    }

    /**
     * 增加几个空行
     */
    public function addEmptyRows($resultList, $num)
    {
        for ($i = 0; $i < $num; $i++) {
            $empty['number']      = ' ';
            $empty['file_number'] = ' ';
            $empty['title']       = '';
            $empty['page_num']    = '';
            $empty['remark']      = '';

            $resultList[] = $empty;
        }
        return $resultList;
    }

    /**
     * 从哪个单元格开始渲染数据，数据集合如 $list
     * @return string
     */
    public function startCell(): string
    {
        return 'A1';
    }

}
